#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <omp.h>
#include "palindromo.h"

#define ARQUIVO 	"./arq/wikipedia.txt"
#define ARQ_PALI	"./resultados/wiki_pal_omp.txt"

#ifndef TBLOCO
#define TBLOCO 4 //padrao 
#endif

#ifndef NTHREADS
#define NTHREADS 4 //padrao
#endif

#define TAM_BUFF NTHREADS*TBLOCO*1024 

char buffer1[TAM_BUFF];
char buffer2[TAM_BUFF];
int palavras, palindromos, primos;
int tam[NTHREADS];


void busca_no_bloco(int lido){
	int pala, pali, pri; 
	int plflag, prflag, th;
	int iniciop, fimp, max;

	pala = pali = pri = 0;

	/*divide o buffer1 carregado igualmente entre as threds, tambem o buffer2 para registrar os palindromos*/
	
	#pragma omp parallel reduction(+: pala, pali, pri) private(th, plflag, prflag, iniciop, fimp, max)
	{
		//calcula a parte do bloco referente a thread		
		th = omp_get_thread_num();
		tam[th] = iniciop =  1024 * TBLOCO * th;
		max = (1024 * TBLOCO) + iniciop;
		if(lido < max) max = lido;

		/* igual a sequencial */

		while(iniciop < max && (UCASE(buffer1[iniciop]) < 'A' ||
				 UCASE(buffer1[iniciop]) > 'Z')) iniciop++;

		while(iniciop < max){

			fimp = iniciop;
			while(fimp < max && (UCASE(buffer1[fimp]) >= 'A' &&
				  UCASE(buffer1[fimp]) <= 'Z')) fimp++;

			if(fimp == max) break;
			pala++;
			plflag = check_palavra( buffer1 + iniciop, fimp - iniciop);

			if(plflag){
				pali++;
				prflag = teste_primo( buffer1 + iniciop, fimp - iniciop);
				if(prflag) pri++;
				buffer1[fimp] = '\0';
				//salva na porção referente a thread do buffer2 para posteriormente ser transferido para o arquivo
				tam[th] += sprintf(buffer2 + tam[th], "%s %d\n", buffer1 + iniciop, prflag);
			}

			iniciop = fimp;
			while(iniciop < max && (UCASE(buffer1[iniciop]) < 'A' ||
				  UCASE(buffer1[iniciop]) > 'Z')) iniciop++;
		}
	}

	palavras += pala;
	palindromos += pali;
	primos += pri;
}


int main(){
	int it, lido;
	int pfd, pfd_resul, j, inicio;
 	unsigned long t1, t2;

	if ((pfd = open(ARQUIVO, O_RDONLY, 0 )) == -1){
	    fprintf(stderr, "Nao foi possivel abrir: %s.\n", ARQUIVO );
	    exit(1);
	}
	if ((pfd_resul = open(ARQ_PALI, O_WRONLY | O_CREAT | O_TRUNC,
					S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
	{
	    fprintf(stderr, "Nao foi possivel abrir: %s.\n", ARQ_PALI );
	    exit(1);
	}

	t1 = clock();

	omp_set_num_threads(NTHREADS);	

	it = 0;
	palavras = palindromos = primos = 0;

	do{
		lido = read(pfd, (void *) buffer1, TAM_BUFF);	//Carrega um bloco
		it++;

		busca_no_bloco(lido);

		//Salva os resultados em arquivo
		for(j=0; j < NTHREADS; j++){
			inicio = 1024 * TBLOCO * j;
			write(pfd_resul, buffer2 + inicio, tam[j] - inicio);
		}

	}
	while(lido == TAM_BUFF);

	t2 = clock();
	printf("\nResultados:\n\n");
	printf("\tTempo total: %lfs\n", ((double) (t2 - t1))/CLOCKS_PER_SEC);
	printf("\tAcessos ao arquivo: %d\n\tPalavras: %d\n\tPalindromos: %d\n",
		  it, palavras, palindromos);
	printf("\tPrimos: %d\n", primos);

	close(pfd);
	close(pfd_resul);

	return 0;
}
